/* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements.  See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF licenses this file to You under the Apache License, Version 2.0
* (the "License"); you may not use this file except in compliance with
* the License.  You may obtain a copy of the License at
*
*     http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/


/*************************************************************************
 * File: event.h
 *************************************************************************
 *\author: starlove
 *************************************************************************/

#ifndef __MLSE_EVENT_EVENT_H__
#define __MLSE_EVENT_EVENT_H__

#include <platform/platform.h>
#include <platform/fixed_allocator.h>

#define __DEFAULT_EVENT_FRAME_TIME__ 30

enum EventTP
{
    ETP_UNKNOWN		= 1,
    ETP_READ_READY	= ETP_UNKNOWN << 1,
    ETP_WRITE_READY	= ETP_UNKNOWN << 2,
    ETP_NEW			= ETP_UNKNOWN << 3,
    ETP_ERROR		= ETP_UNKNOWN << 4,
    ETP_IOERROR		= ETP_UNKNOWN << 5
};

#pragma pack(1)
//////////////////////////////////////////////////////////////////////////
/// !!! 切记千万不要设置ETP_NEW与ETP_READ_READY和ETP_WRITE_READY协同
//////////////////////////////////////////////////////////////////////////
typedef struct __EVENT
{
    int events;
    int event_sets;
    void *op;
    EVHANDLE hd;
    void *data;
    void *ptr;
    unsigned int datasize;
    void *next;
} EVENT, *LPEVENT;

#pragma pack()

extern CFixedAllocator<EVENT> g_Events;
/// Create a Event
extern LPEVENT Create_Event();
/// Destory a Event
extern void Destory_Event(LPEVENT pev);

class IEventProcessor
{
public:
    virtual ~IEventProcessor() {};
    virtual void OnEvent(LPEVENT, int) = 0;
protected:
private:
};

typedef IEventProcessor *LPEventProcessor;

class IEventIO
{
public:
    virtual ~IEventIO() {};
    //////////////////////////////////////////////////////////////////////////
    /// Query io_events
    //////////////////////////////////////////////////////////////////////////
    virtual LPEVENT Query(unsigned int &, unsigned int) = 0;
    //////////////////////////////////////////////////////////////////////////
    /// Bind io-handle to IO
    //////////////////////////////////////////////////////////////////////////
    virtual bool Bind(EVHANDLE) = 0;
    //////////////////////////////////////////////////////////////////////////
    /// Post a event to the IO-Handle(maybe not be support)
    //////////////////////////////////////////////////////////////////////////
    virtual void Post(LPEVENT) = 0;
	/// Return io handle
	virtual HANDLE GetIOHandle() = 0;
    //////////////////////////////////////////////////////////////////////////
    /// Set the IO-Handle
    //////////////////////////////////////////////////////////////////////////
    virtual bool Init(HANDLE) = 0;
    virtual bool Init() = 0;
protected:
private:
};

typedef IEventIO *LPEventIO;

typedef std::map<EVHANDLE, EVENT> EVENTS;
typedef std::pair<EVHANDLE, EVENT> EVENTPAIR;

class CEventDispatcher
{
public:
    CEventDispatcher();
    bool Init(LPEventIO io, unsigned int frame_time = __DEFAULT_EVENT_FRAME_TIME__);
    void Lookup();
    //////////////////////////////////////////////////////////////////////////
    /// Bind io-handle to IO
    //////////////////////////////////////////////////////////////////////////
    bool Bind(EVHANDLE hd);
	/// Return io handle
    void Abort();
    void Post(LPEVENT ev);
    LPEventIO GetIO();
protected:
private:
    LPEventIO m_io;
    EVENTS m_evs;
    unsigned int m_frame_time;
    bool m_running;
};

#endif
